﻿namespace EyeOpen.Mapping
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Xml.Linq;

    public abstract class BaseMapper : IMapper<XElement>
    {        
        /// <summary>
        /// Determines whether [is base type] [the specified property].
        /// </summary>
        /// <param name="property">The property.</param>
        /// <returns>
        /// 	<c>true</c> if [is base type] [the specified property]; otherwise, <c>false</c>.
        /// </returns>
        public static bool IsBaseType(Type type)
        {
            if (type == typeof(Guid))
            {
                return true;
            }

            int typeCode = (int)Type.GetTypeCode(type);
            return ((typeCode >= 2) && (typeCode <= 18));
        }

        /// <summary>
        /// Gets the types.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <param name="baseContract">The base contract.</param>
        /// <returns></returns>
        public static IList<Type> GetTypes(Assembly assembly)
        {
            return assembly.GetTypes().ToList();
        }

        /// <summary>
        /// Generates the mappings.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <returns></returns>
        public virtual IDictionary<Type, XElement> GenerateMappings(Assembly assembly)
        {
            return this.GenerateMappings(assembly, type => true);
        }

        /// <summary>
        /// Generates the mappings.
        /// </summary>
        /// <typeparam name="T">The base interface or class.</typeparam>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <returns></returns>
        public IDictionary<Type, XElement> GenerateMappings<T>(Assembly assembly)
        {
            return this.GenerateMappings(assembly, type => type.IsSubclassOf(typeof(T)));
        }

        /// <summary>
        /// Generates the mapping.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public abstract XElement GenerateMappings(Type type);

        /// <summary>
        /// Generates the mappings.
        /// </summary>
        /// <param name="assemblyPath">The assembly path.</param>
        /// <param name="baseContract">The base contract.</param>
        /// <returns></returns>
        protected IDictionary<Type, XElement> GenerateMappings(Assembly assembly, Func<Type, bool> predicate)
        {
            Dictionary<Type, XElement> mapping = new Dictionary<Type, XElement>();
            IList<Type> types = GetTypes(assembly);

            types
                .Where(predicate)
                .ToList()
                .ForEach(type => mapping.Add(type, this.GenerateMappings(type)));

            return mapping;
        }
    }
}